package com.lpy.service.impl;

import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.lpy.mapper.*;
import com.lpy.pojo.domain.*;
import com.lpy.pojo.entity.StockBusiness;
import com.lpy.pojo.vo.StockInfoConfig;
import com.lpy.service.StockService;
import com.lpy.utils.DateTimeUtil;
import com.lpy.utils.RequestInfoUtil;
import com.lpy.vo.resp.PageResult;
import com.lpy.vo.resp.R;
import com.lpy.vo.resp.ResponseCode;
import org.checkerframework.checker.units.qual.A;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;


import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lpy
 * @date 2025/2/13
 * @Description
 */
@Service
public class StockServiceImpl implements StockService {

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockInfoConfig stockInfoConfig;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private Cache<String, Object> caffeineCache;

    @Override
    public R<List<InnerMarketDomain>> innerIndexAll() {
//从缓存中加载数据，如果不存在，则走补偿策略获取数据，并存入本地缓存
        R<List<InnerMarketDomain>> data = (R<List<InnerMarketDomain>>) caffeineCache.get("innerMarketInfos", key -> {
            //如果不存在，则从数据库查询
            //1.获取最新的股票交易时间点
            Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
            Date lastDate2 = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

            LocalDateTime localDateTime = lastDate.toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();

            // 判断是否为15点
            if (localDateTime.getHour() == 15) {
                // 增加30分钟
                LocalDateTime newDateTime = localDateTime.plusMinutes(30);

                // 将 LocalDateTime 转换回 Date
                lastDate2 = Date.from(newDateTime.atZone(ZoneId.systemDefault()).toInstant());
            }

            List<Date> dates = new ArrayList<>();
            //TODO 伪造数据，后续删除
            lastDate = DateTime.parse("2025-03-05 13:56:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            lastDate2 = DateTime.parse("2025-03-05 13:56:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

            dates.add(lastDate);
            dates.add(lastDate2);
            //2.获取国内大盘编码集合
            List<String> innerCodes = stockInfoConfig.getInner();
            //3.调用mapper查询
            List<InnerMarketDomain> infos = stockMarketIndexInfoMapper.getMarketInfo(innerCodes, dates);
            //4.响应
            return R.ok(infos);
        });
        return data;

    }

    @Override
    public R<List<StockBlockDomain>> sectorAll() {
        //获取股票最新交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
//        // 将 Date 转换为 LocalDateTime
//        LocalDateTime localDateTime = lastDate.toInstant()
//                .atZone(ZoneId.systemDefault())
//                .toLocalDateTime();
//
//// 修改时分值为 13:05
//        localDateTime = localDateTime.withHour(13).withMinute(5);
//
//// 将 LocalDateTime 转换回 Date
//        lastDate = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        //TODO mock数据,后续删除
        lastDate = DateTime.parse("2025-03-05 11:13:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.调用mapper接口获取数据
        List<StockBlockDomain> infos = stockBlockRtInfoMapper.sectorAll(lastDate);
        //2.组装数据
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA.getMessage());
        }
        return R.ok(infos);
    }

    @Override
    public R<PageResult> getStockPageInfo(Integer page, Integer pageSize) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);

        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        curDate = DateTime.parse("2025-03-05 13:56:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //查询
        List<StockUpdownDomain> infos = stockRtInfoMapper.getNewestStockInfo(curDate);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }

        //组装PageInfo对象
        PageResult<StockUpdownDomain> pageResult = new PageResult<>(new PageInfo<>(infos));

        return R.ok(pageResult);
    }

    @Override
    public R<List<StockUpdownDomain>> getStockInfo() {
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        curDate = DateTime.parse("2025-03-05 13:56:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //查询
        List<StockUpdownDomain> infos = stockRtInfoMapper.getNewestStockInfoLimit(curDate);
        if (CollectionUtils.isEmpty(infos)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }

        return R.ok(infos);
    }

    @Override
    public R<Map> getStockUpdownCount() {
        //1.获取最新的交易时间范围 openTime  curTime
        //1.1 获取最新股票交易时间点
        DateTime curDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date curTime = curDateTime.toDate();
        //TODO
        curTime= DateTime.parse("2025-03-05 13:56:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2 获取最新交易时间对应的开盘时间
        DateTime openDate = DateTimeUtil.getOpenDate(curDateTime);
        Date openTime = openDate.toDate();
        //TODO
        openTime= DateTime.parse("2025-03-05 10:14:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.查询涨停数据
        //约定mapper中flag入参： 1-》涨停数据 0：跌停
        List<Map> upCounts = stockRtInfoMapper.getStockUpdownCount(openTime, curTime, 1);
        //3.查询跌停数据
        List<Map> dwCounts = stockRtInfoMapper.getStockUpdownCount(openTime, curTime, 0);
        //4.组装数据
        HashMap<String, List> mapInfo = new HashMap<>();
        mapInfo.put("upList", upCounts);
        mapInfo.put("downList", dwCounts);
        //5.返回结果
        return R.ok(mapInfo);
    }

    @Override
    public void stockExport(HttpServletResponse response, Integer page, Integer pageSize) {
        try {
            //1.获取最近最新的一次股票有效交易时间点（精确分钟）
            Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
            //因为对于当前来说，我们没有实现股票信息实时采集的功能，所以最新时间点下的数据
            //在数据库中是没有的，所以，先临时指定一个假数据,后续注释掉该代码即可
            curDate=DateTime.parse("2025-03-05 13:56:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            //2.设置分页参数 底层会拦截mybatis发送的sql，并动态追加limit语句实现分页
            PageHelper.startPage(page, pageSize);
            //3.查询
            List<StockUpdownDomain> infos = stockRtInfoMapper.getNewestStockInfo(curDate);
            //如果集合为空，响应错误提示信息
            if (CollectionUtils.isEmpty(infos)) {
                //响应提示信息
                RequestInfoUtil.setUtf8(response);
                R<Object> r = R.error(ResponseCode.NO_RESPONSE_DATA);
                response.setContentType("application/json");
                response.setCharacterEncoding("utf-8");
                response.getWriter().write(new ObjectMapper().writeValueAsString(r));
                return;
            }
            //设置响应excel文件格式类型
            response.setContentType("application/vnd.ms-excel");
            //2.设置响应数据的编码格式
            response.setCharacterEncoding("utf-8");
            //3.设置默认的文件名称
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode("stockRt", "UTF-8");
            //设置默认文件名称：兼容一些特殊浏览器
            response.setHeader("content-disposition", "attachment;filename=" + fileName + ".xlsx");
            //4.响应excel流
            EasyExcel
                    .write(response.getOutputStream(), StockUpdownDomain.class)
                    .sheet("股票信息")
                    .doWrite(infos);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("当前导出数据异常，当前页：{},每页大小：{},异常信息：{}" + page + pageSize + e.getMessage());
        }
    }

    @Override
    public R<Map> stockTradeVol4InnerMarket() {
        //1.获取T日的开始时间和结束时间
        //1.1 获取最近股票有效交易时间点--T日时间范围
        DateTime lastDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        DateTime openDateTime = DateTimeUtil.getOpenDate(lastDateTime);
        //转化成java中Date,这样jdbc默认识别
        Date startTime4T = openDateTime.toDate();
        Date endTime4T = lastDateTime.toDate();
        //TODO  mock数据
        startTime4T=DateTime.parse("2022-01-03 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        endTime4T=DateTime.parse("2022-01-03 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //1.获取T-1日的开始时间和结束时间
        //1.1 获取最近股票有效交易时间点--T日时间范围
        // 获取前一天的时间
        DateTime lastDateTime2 = lastDateTime.minusDays(1); // 减去一天
        DateTime openDateTime2 = DateTimeUtil.getOpenDate(lastDateTime2); // 获取前一天的开盘时间

        // 转化成 java.util.Date
        Date startTime4T2 = openDateTime2.toDate();
        Date endTime4T2 = lastDateTime2.toDate();
        //TODO  mock数据
        startTime4T2=DateTime.parse("2022-01-02 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        endTime4T2=DateTime.parse("2022-01-02 14:40:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        List<String> inner = stockInfoConfig.getInner();

        List<Map> stockTradeVol1 = stockMarketIndexInfoMapper.getStockTradeVol(inner, startTime4T, endTime4T);
        List<Map> stockTradeVol2 = stockMarketIndexInfoMapper.getStockTradeVol(inner, startTime4T2, endTime4T2);

        if (CollectionUtils.isEmpty(stockTradeVol1) || CollectionUtils.isEmpty(stockTradeVol2)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }

        Map<String, List> res = new HashMap<>();
        res.put("amtList", stockTradeVol1);
        res.put("yesAmtList", stockTradeVol2);

        return R.ok(res);
    }

    @Override
    public R<Map> stockUpDownScopeCount() {
        //1.获取股票最新一次交易的时间点
        Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //mock data
        curDate=DateTime.parse("2025-03-05 13:56:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        List<Map> maps = stockRtInfoMapper.getStockUpDownSectionByTime(curDate);
        if (CollectionUtils.isEmpty(maps)) {
            return R.error(ResponseCode.NO_RESPONSE_DATA);
        }
        List<String> orderSections = stockInfoConfig.getUpDownRange();

        List<Map> orderMaps = orderSections.stream().map(title -> {
            Map mp = null;
            Optional<Map> optional = maps.stream().filter(m -> m.containsValue(title)).findFirst();
            if (optional.isPresent()) {
                mp = optional.get();
            } else {
                mp = new HashMap();
                mp.put("title", title);
                mp.put("count", 0);
            }
            return mp;
        }).collect(Collectors.toList());
        HashMap<String, Object> res = new HashMap<>();
        res.put("time", curDate);
        res.put("infos", orderMaps);
        return R.ok(res);
    }

    @Override
    public R<List<Stock4MinuteDomain>> stockScreenTimeSharing(String code) {
        //1.获取最近最新的交易时间点和对应的开盘日期
        //1.1 获取最近有效时间点
        DateTime lastDate4Stock = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = lastDate4Stock.toDate();
        //TODO mockdata
        endTime=DateTime.parse("2021-12-30 14:47:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();

        //1.2 获取最近有效时间点对应的开盘日期
        DateTime openDateTime = DateTimeUtil.getOpenDate(lastDate4Stock);
        Date startTime = openDateTime.toDate();
        //TODO MOCK DATA
        startTime=DateTime.parse("2021-12-30 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.根据股票code和日期范围查询
        List<Stock4MinuteDomain> list = stockRtInfoMapper.getStockInfoByCodeAndDate(code, startTime, endTime);
        //判断非空处理
        if (CollectionUtils.isEmpty(list)) {
            list = new ArrayList<>();
        }
        //3.返回响应数据
        return R.ok(list);
    }

    @Override
    public R<List<Stock4EvrDayDomain>> stockCreenDkLine(String code) {
        //1.获取查询的日期范围
        //1.1 获取截止时间
        DateTime endDateTime = DateTimeUtil.getLastDate4Stock(DateTime.now());
        Date endTime = endDateTime.toDate();
        //TODO MOCKDATA
        endTime=DateTime.parse("2022-01-07 15:00:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //1.2 获取开始时间
        DateTime startDateTime = endDateTime.minusDays(10);
        Date startTime = startDateTime.toDate();
        //TODO MOCKDATA
        startTime=DateTime.parse("2022-01-01 09:30:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.调用mapper接口获取查询的集合信息-方案1
        List<Stock4EvrDayDomain> data = stockRtInfoMapper.getStockInfo4EvrDay(code, startTime, endTime);
        //3.组装数据，响应
        return R.ok(data);
    }

    @Override
    public R<List<OuterMarketDomain>> getOuterMarketIndexInfo() {
        //从缓存中加载数据，如果不存在，则走补偿策略获取数据，并存入本地缓存
        R<List<OuterMarketDomain>> data = (R<List<OuterMarketDomain>>) caffeineCache.get("outerMarketInfos", key -> {
            //如果不存在，则从数据库查询
            //1.获取最新的股票交易时间点
            Date curDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
            //TODO 伪造数据，后续删除
            curDate=DateTime.parse("2025-03-05 10:21:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
            //2.获取国内大盘编码集合
            List<String> outerCodes = stockInfoConfig.getOuter();
            //3.调用mapper查询
            List<OuterMarketDomain> infos = stockOuterMarketIndexInfoMapper.getMarketInfo(curDate);
            //4.响应
            return R.ok(infos);
        });
        return data;
    }

    @Override
    public R<List<SearchDomain>> getSearchStocks(String searchStr) {
        R<List<SearchDomain>> infos = (R<List<SearchDomain>>) caffeineCache.get("search" + searchStr, key -> {
            //调用mapper查询
            List<SearchDomain> data = stockRtInfoMapper.getSearchStocks(searchStr);
            return R.ok(data);
        });

        //响应
        return infos;
    }

    @Override
    public R<DescriptionDomain> getDescription(String code) {
        R<DescriptionDomain> infos = (R<DescriptionDomain>) caffeineCache.get("description4" + code, key -> {
            DescriptionDomain data = stockBusinessMapper.getDescription(code);
            return R.ok(data);
        });
        return infos;
    }

    @Override
    public R<Stock4WeeklineDomain> getWeekKline(String code) {
        //1.获取最新的股票交易时间点
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();
        //TODO 伪造数据，后续删除
        lastDate=DateTime.parse("2022-07-07 14:48:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
        //2.获取国内个股周营集合
        Stock4WeeklineDomain wd = stockRtInfoMapper.getWeekKline(code, lastDate);
        if (wd == null) {
            return R.error("获取个股周k线失败");
        }
        return R.ok(wd);
    }

    @Override
    public R<Stock4MinuteDomain> getScreenSecondDetail(String code) {
        Date lastDate = DateTimeUtil.getLastDate4Stock(DateTime.now()).toDate();

        Stock4MinuteDomain data = stockRtInfoMapper.getScreenDetail(code, lastDate);
        if (data == null) {
            return R.error("获取个股详情失败");
        }
        return R.ok(data);
    }

    @Override
    public R<List<Stock4MinuteDomain>> getScreenSecond(String code) {

        List<Stock4MinuteDomain> info = stockRtInfoMapper.getScreenSecond(code);
        if (info == null) {
            return R.error("获取个股详情失败");
        }
        return R.ok(info);
    }


}
